package com.hundsun.cprs.yyt.service.order.service.impl;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.hundsun.cprs.yyt.util.StringUtil;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.enums.EnumAreaCode;
import com.hundsun.cprs.yyt.common.enums.EnumBusinessCode;
import com.hundsun.cprs.yyt.common.exception.ServiceCodeException;
import com.hundsun.cprs.yyt.service.account.domain.Account;
import com.hundsun.cprs.yyt.service.account.enums.EnumQuotaTransType;
import com.hundsun.cprs.yyt.service.account.service.AccountQuoteLimitService;
import com.hundsun.cprs.yyt.service.account.service.AccountService;
import com.hundsun.cprs.yyt.service.common.dto.FundBatchRequest;
import com.hundsun.cprs.yyt.service.common.dto.FundMoneyInfo;
import com.hundsun.cprs.yyt.service.common.dto.UserAccountDTO;
import com.hundsun.cprs.yyt.service.common.enums.EnumFundBidCode;
import com.hundsun.cprs.yyt.service.common.service.RemoteTradeFundService;
import com.hundsun.cprs.yyt.service.dilivery.service.DeliveryService;
import com.hundsun.cprs.yyt.service.dilivery.service.DiliveryAddressService;
import com.hundsun.cprs.yyt.service.goods.domain.GoodsSpecs;
import com.hundsun.cprs.yyt.service.goods.domain.query.GoodsQuery;
import com.hundsun.cprs.yyt.service.goods.dto.GoodsInfo;
import com.hundsun.cprs.yyt.service.goods.enums.EnumQuoteRewardPolicy;
import com.hundsun.cprs.yyt.service.goods.service.GoodsService;
import com.hundsun.cprs.yyt.service.goods.service.GoodsSkuService;
import com.hundsun.cprs.yyt.service.order.dao.OrderDao;
import com.hundsun.cprs.yyt.service.order.dao.OrderItemDao;
import com.hundsun.cprs.yyt.service.order.domain.Order;
import com.hundsun.cprs.yyt.service.order.domain.OrderItem;
import com.hundsun.cprs.yyt.service.order.domain.query.OrderInfoQuery;
import com.hundsun.cprs.yyt.service.order.domain.query.OrderQuery;
import com.hundsun.cprs.yyt.service.order.dto.DeliveryMethod;
import com.hundsun.cprs.yyt.service.order.dto.GoodsItem;
import com.hundsun.cprs.yyt.service.order.dto.OrderInfo;
import com.hundsun.cprs.yyt.service.order.enums.EnumOrderSNCode;
import com.hundsun.cprs.yyt.service.order.enums.EnumsOrderStatus;
import com.hundsun.cprs.yyt.service.order.service.OrderService;
import com.hundsun.cprs.yyt.service.quota.domain.Quota;
import com.hundsun.cprs.yyt.service.quota.domain.QuotaHold;
import com.hundsun.cprs.yyt.service.quota.service.QuotaHoldService;
import com.hundsun.cprs.yyt.service.quota.service.QuotaService;
import com.hundsun.cprs.yyt.service.rabbit.RoutingKeyConstants;
import com.hundsun.cprs.yyt.service.system.domain.BussinessParam;
import com.hundsun.cprs.yyt.service.system.enums.EnumBussinessParam;
import com.hundsun.cprs.yyt.service.system.service.BusinessParamHelper;
import com.hundsun.cprs.yyt.service.system.service.BussinessParamService;
import com.hundsun.cprs.yyt.service.trade.domain.TradeEntrust;
import com.hundsun.cprs.yyt.service.trade.domain.TradeMatchDetail;
import com.hundsun.cprs.yyt.service.trade.domain.query.TradeEntrustQuery;
import com.hundsun.cprs.yyt.service.trade.enums.EnumEntustBSType;
import com.hundsun.cprs.yyt.service.trade.enums.EnumTradeEntrustStatus;
import com.hundsun.cprs.yyt.service.trade.service.TradeEntrustService;
import com.hundsun.cprs.yyt.service.trade.service.TradeMatchService;
import com.hundsun.cprs.yyt.util.DateUtil;
import com.hundsun.cprs.yyt.util.SequenceUtils;

@Service
public class OrderServiceImpl extends BaseService implements OrderService {

    private static final String USER_QOUTE_USE_LIMIT = "user_qoute_use_limit";
    private static final Long DEFAULT_USER_QOUTE_USE_LIMIT = 1000L;

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private OrderItemDao orderItemDao;
    @Autowired
    private GoodsSkuService skuService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private RemoteTradeFundService fundService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private AccountQuoteLimitService accountQuoteLimitService;
    @Autowired
    private BussinessParamService bussinessParamService;
    @Autowired
    private DeliveryService deliveryService;
    @Autowired
    private DiliveryAddressService diliveryAddressService;
    @Autowired
    private TradeMatchService tradeMatchService;
    @Autowired
    private TradeEntrustService tradeEntrustService;
    @Autowired
    private QuotaHoldService quotaHoldService;
    @Autowired
    private QuotaService quotaService;
    @Autowired
    private GoodsService goodsService;
    @Value("${goldenFlower_user_number_segment}")
    private String goldenFlowerNumberSegment;

    @Override
    @Transactional
    public OrderInfo createOrder(UserAccountDTO user, GoodsItem item, DeliveryMethod deliveryMethod, String memo) {
        Assert.notNull(user, "user must not be null");
        Assert.notNull(item, "goodsItem must not be null");
        Assert.notNull(deliveryMethod, "deliveryMethod must be not null");
        if (deliveryMethod.isDelivery()) {
            Assert.notNull(deliveryMethod.getReceiver(), "receiver must be not null");
        }
        if (item.isFromRetailArea() && deliveryMethod.isEntrust()) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1509);
        }
        GoodsSpecs sku = item.getSku();
        //校验库存充足
        if (item.getQuantity() > sku.getAvailableStock()) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1510);
        }

        //金莱花购买限制
        validateGoldenFlower(item.getGoods().getGoodsCode(), user);

        //构建订单
        OrderInfo order = buildOrderInfo(user, item, deliveryMethod, memo);
        //校验支付金额
        checkBalance(order);
        //校验配额
        checkQuota(order);
        //检查下单规则
        if (item.isFromWholesaleArea()) {
            //校验用户当日消费配额是否达到上限
            //validateQuoteLimit(order.getUserId(),order.getQuotaAmount());

            //校验批发区限购规则，每人最多买几个
            validateWholesaleLimit(order, item);

            //校验用户配额类型的挂售量限制
            if (deliveryMethod.isEntrust()) {
                validateGoodsLimit(order.getUserId(), order.getOrderItems().get(0).getPayQuotaId(), order.getQuantity());
            }
        } else {
            //校验零售区限购规则，每人每天最多买几个
            validateRetailLimit(order, item);
        }
        //预占库存
        skuService.addAllocatedStock(sku.getId(), item.getQuantity());
        //保存订单
        saveOrderInfo(order);
        //配额扣除
        paymentQuota(order);
        //订单支付
        payment(order);
        //更新订单
        orderDao.updateByPrimaryKey(order);
        //通知订单已支付
        rabbitTemplate.convertAndSend(RoutingKeyConstants.YYT_ORDER_PAID, order);
        return order;
    }

    //校验批发区限购规则，每人最多买几个
    protected void validateWholesaleLimit(OrderInfo orderInfo, GoodsItem item) {
        if (item.getGoods().getWholesaleLimit() != null &&
                !item.getGoods().getWholesaleLimit().equals(0L)) {
            OrderInfoQuery query = new OrderInfoQuery();
            query.setUserId(orderInfo.getUserId());
            query.setAreaCode(EnumAreaCode.WHOLESALE_AREA.getCode());
            query.setGoodsCode(item.getGoods().getGoodsCode());
            this.selectOrderInfoByPage(query);
            Long amount = orderInfo.getQuantity().longValue();
            if (query.getTotalCount() > 0) {
                //累计本次下单数量和之前下单数量值和
                for (OrderInfo temp : query.getData()) {
                    amount += temp.getQuantity().longValue();
                }
            }
            if (amount > item.getGoods().getWholesaleLimit()) {
                Long remainAmount = item.getGoods().getWholesaleLimit() - amount + orderInfo.getQuantity().longValue();
                remainAmount = remainAmount < 0 ? 0 : remainAmount;
                String info = MessageFormat.format(EnumBusinessCode.BUSINESS_1041.getErrorInfo(), remainAmount);
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1041.getErrorNo(), info);
            }
        }
    }

    //校验零售区限购规则，每人每天最多买几个
    protected void validateRetailLimit(OrderInfo orderInfo, GoodsItem item) {
        if (item.getGoods().getRetailLimit() != null &&
                !item.getGoods().getRetailLimit().equals(0L)) {
            OrderInfoQuery query = new OrderInfoQuery();
            query.setUserId(orderInfo.getUserId());
            query.setAreaCode(EnumAreaCode.RETAIL_AREA.getCode());
            query.setGoodsCode(item.getGoods().getGoodsCode());
            query.setStartDate(DateUtil.getBeginOfDay(new Date()));
            query.setEndDate(DateUtil.getEndOfDay(new Date()));
            this.selectOrderInfoByPage(query);
            Long amount = orderInfo.getQuantity().longValue();
            if (query.getTotalCount() > 0) {
                for (OrderInfo temp : query.getData()) {
                    amount += temp.getQuantity().longValue();
                }
            }
            if (amount > item.getGoods().getRetailLimit()) {
                Long remainAmount = item.getGoods().getRetailLimit() - amount + orderInfo.getQuantity().longValue();
                remainAmount = remainAmount < 0 ? 0 : remainAmount;
                String info = MessageFormat.format(EnumBusinessCode.BUSINESS_1042.getErrorInfo(), remainAmount);
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1042.getErrorNo(), info);
            }
        }
    }

    //创建订单信息
    private OrderInfo buildOrderInfo(UserAccountDTO user, GoodsItem item, DeliveryMethod deliveryMethod, String memo) {
        GoodsSpecs sku = item.getSku();
        //生成订单
        OrderInfo order = new OrderInfo();
        order.setDeliveryType(deliveryMethod.getDiliveryType());
        if (deliveryMethod.isDelivery()) {
            order.setConsignee(deliveryMethod.getReceiver().getConsigneeName());
            order.setPhone(deliveryMethod.getReceiver().getPhone());
        } else if (deliveryMethod.isSelfGet()) {
            order.setConsignee(deliveryMethod.getSeleGetName());
            order.setPhone(deliveryMethod.getSelfGetPhone());
            order.setSelfGetTime(DateUtil.strToDate(deliveryMethod.getSelfGetTime(), "yyyy-MM-dd"));
        }
        if (!deliveryMethod.isEntrust()) {
            String address = new StringBuffer()
                    .append(deliveryMethod.getReceiver().getProvinceAddress())
                    .append(deliveryMethod.getReceiver().getMunicipalAddress())
                    .append(deliveryMethod.getReceiver().getCountyAddress())
                    .append(deliveryMethod.getReceiver().getDiliveryAddress())
                    .toString();
            order.setAddress(address);
        }
        order.setSn(SequenceUtils.generateSequence(SequenceUtils.BIZ_ORDER));//TODO 需要定义订单编号
        order.setOrderDate(new Date());
        order.setAreaCode(item.getSku().getAreaCode());
        order.setFreight(BigDecimal.ZERO.longValue());
        order.setMemo(memo);
        order.setFundAccount(user.getFundAccount());
        order.setUserId(user.getId());
        order.setUserName(user.getName());
        order.setStatus(EnumsOrderStatus.WAIT_PAY.getStatus());
        order.setCommission(BigDecimal.ZERO.longValue());
        order.setSellerId(new Long(item.getGoods().getOrganizationId()));
        if (deliveryMethod.getReceiver() != null) {
            order.setDiliveryId(deliveryMethod.getReceiver().getId());
        }

        //生成订单商品详情
        OrderItem orderItem = new OrderItem();
        orderItem.setGoodsId(new Long(item.getGoods().getId()));
        orderItem.setGoodsCode(item.getGoods().getGoodsCode());
        orderItem.setGoodsName(item.getGoods().getGoodsName());
        orderItem.setCostPrice(item.getGoods().getCostPrice().longValue());
        orderItem.setPrice(sku.getGoodsPrice().longValue());
        orderItem.setQuantity(item.getQuantity());
        orderItem.setPayQuotaId(item.getGoods().getPayQuotaId());
        orderItem.setQuotaAmount(item.getQuotaAmount());
        orderItem.setSkuId(new Long(sku.getId()));
        orderItem.setThumbnail(item.getGoods().obtainThumbnail());
        //TODO:去除交易送积分的业务
        //orderItem.addIntegralRewardRate(item.getIntegralRewardRate());
        orderItem.addIntegralRewardRate(BigDecimal.ZERO.doubleValue());
        orderItem.setRewardQuotaId(item.getGoods().getRewardQuotaId());
        if (Integer.compare(item.getGoods().getQuotaRewardPolicy(), EnumQuoteRewardPolicy.RATE_REWARD.ordinal()) == 0) {
            orderItem.addQuotaRewardRate(item.getQuotaRewardRate());
        } else if (Integer.compare(item.getGoods().getQuotaRewardPolicy(), EnumQuoteRewardPolicy.FIX_AMOUNT_REWARD.ordinal()) == 0) {
            orderItem.addQuotaRewardAmount(item.getGoods().getQuotaRewardAmount());
        }
        order.addOrderItem(orderItem);
        return order;
    }

    // 检查余额
    private void checkBalance(OrderInfo order) {
        // 校验余额是否足够
        Long price = order.getPrice();
        FundMoneyInfo fundMoney = fundService.getFundMoneyInfoByFundAccount(order.getFundAccount());
        if (fundMoney == null) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1003);
        }
        if (price > fundMoney.getCanUseBalance()) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1101);
        }
    }

    // 检查需支付的配额
    private void checkQuota(OrderInfo order) {
        Long quotaAmount = order.getQuotaAmount();
        if (quotaAmount == 0) {
            return;
        }
        Account account = accountService.getAccountByUserId(order.getUserId());
        if (account == null) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1400);
        }
        Quota payQuota = quotaService.selectQuoteById(order.getOrderItems().get(0).getPayQuotaId());
        if (payQuota == null || "Y".equalsIgnoreCase(payQuota.getIsDeleted())) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1402);
        }
        QuotaHold quotaHold = quotaHoldService.getQuoteHoldByUserAndQuoteId(order.getUserId(), order.getOrderItems().get(0).getPayQuotaId());
        if (quotaHold == null || quotaAmount > quotaHold.getCanUseAmount()) {
            throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1401);
        }
    }

    protected void saveOrderInfo(OrderInfo order) {
        orderDao.insert(order);
        for (OrderItem orderItem : order.getOrderItems()) {
            //设置关联订单ID
            orderItem.setOrderId(order.getId());
            orderItemDao.insert(orderItem);
        }
    }

    protected void paymentQuota(OrderInfo order) {
        if (order.getQuotaAmount() > 0) {
            quotaHoldService.deductQuota(order.getUserId(),
                    order.getOrderItems().get(0).getPayQuotaId(),
                    order.getQuotaAmount(),
                    EnumQuotaTransType.TRANS_0101.getCode(), "批发区下单扣减配额");
            //accountService.deductQuota(order.getUserId(), order.getQuotaAmount(),EnumQuotaTransType.TRANS_0101.getCode(),"批发区下单扣减配额");
            //将用户消费的配额放入缓存
            //accountQuoteLimitService.addUserQuoteToCache(order.getUserId(),order.getQuotaAmount());
        }
    }

    protected void payment(OrderInfo order) {
        if (order.getPrice() > 0) {
            boolean isWholesaleArea = EnumAreaCode.WHOLESALE_AREA.getCode().equals(order.getAreaCode());
            FundBatchRequest request = FundBatchRequest.builder("system", EnumOrderSNCode.getOrderFundSN(order.getSn(), EnumOrderSNCode.FUND_OUT),
                    MessageFormat.format("[{0}({1})]订单支付", isWholesaleArea ? EnumAreaCode.WHOLESALE_AREA.getDesc() : EnumAreaCode.RETAIL_AREA.getDesc(),
                            order.getOrderItems().get(0).getGoodsName()));
            request.addTask(order.getFundAccount(), EnumFundBidCode.CFUND_170201, order.getSn(), order.getPrice());
            fundService.batchExecute(request);
        }
        //更新支付时间
        order.setPayAmount(order.getPrice());
        order.setPayDate(new Date());
        order.setStatus(EnumsOrderStatus.PAID.getStatus());
    }

    protected void validateQuoteLimit(Long userID, Long quotaAmount) {
        Long usedQuote = accountQuoteLimitService.getUserUsedQuoteCurrent(userID);
        Long currentUsedQuote = usedQuote + quotaAmount;
        //获取配置的配额每日消费上限
        BussinessParam bussinessParam = bussinessParamService.getBussinessParamByKey(USER_QOUTE_USE_LIMIT);
        if (bussinessParam == null) {
            if (currentUsedQuote > DEFAULT_USER_QOUTE_USE_LIMIT) {
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1027.getErrorNo(), EnumBusinessCode.BUSINESS_1027.getErrorInfo());
            }
        } else {
            if (currentUsedQuote > Long.parseLong(bussinessParam.getBussinessValue())) {
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1027.getErrorNo(), EnumBusinessCode.BUSINESS_1027.getErrorInfo());
            }
        }
    }

    protected void validateGoodsLimit(Long userId, Long payQuotaId, int amount) {
        Quota payQuota = quotaService.selectQuoteById(payQuotaId);
        if (payQuota.getTradeAmountLimit() > 0) {
            TradeEntrustQuery query = new TradeEntrustQuery();
            query.setUserId(userId);
            query.setGoodsCodeArray(obtainLimitGoodsCodes(payQuota.getId()));
            query.setEntrustBs(EnumEntustBSType.SELL.getCode().toString());
            long haveTradeAmount = tradeEntrustService.getTradeQuantitySumByQuery(query);

            if (Long.compare(payQuota.getTradeAmountLimit(), amount + haveTradeAmount) < 0) {
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1038.getErrorNo(), EnumBusinessCode.BUSINESS_1038.getErrorInfo());
            }
        }
    }

    private String[] obtainLimitGoodsCodes(Long payQuotaId) {
        GoodsQuery query = new GoodsQuery();
        query.setAreaCode(EnumAreaCode.WHOLESALE_AREA.getCode());
        query.setPayQuotaId(payQuotaId);
        List<GoodsInfo> result = goodsService.queryGoodsByList(query);
        if (result != null) {
            List<String> goodsCodeList = new ArrayList<String>(result.size());
            for (GoodsInfo item : result) {
                goodsCodeList.add(item.getGoodsCode());
            }
            return goodsCodeList.toArray(new String[]{});
        }
        return null;
    }

    @Override
    public void selectByPage(OrderQuery query) {
        List<Order> result = orderDao.selectByQuery(query);
        query.compatible(result);
    }

    @Override
    public void selectOrderInfoByPage(OrderInfoQuery query) {
        List<OrderInfo> result = orderDao.selectOrderInfoByQuery(query);
        query.compatible(result);
    }

    @Override
    public void selectOrderInfoByPageExt(OrderInfoQuery query) {
        List<OrderInfo> result = orderDao.selectOrderInfoByQueryExt(query);
        query.compatible(result);
    }

    @Override
    @Transactional
    public void updateOrder(OrderInfo order) {
        orderDao.updateByPrimaryKey(order);
        for (OrderItem item : order.getOrderItems()) {
            orderItemDao.updateByPrimaryKey(item);
        }
    }

    @Override
    public OrderInfo selectOrderInfoById(Long orderId) {
        OrderInfo orderInfo = orderDao.selectOrderInfoById(orderId);
        if (orderInfo == null) {
            return null;
        }
        //填充物流信息
        orderInfo.setDelivery(deliveryService.selectDeliveryInfo(orderInfo.getId()));
        //填充提货地址信息
        if (orderInfo.getDiliveryId() != null) {
            orderInfo.setDiliveryAddress(diliveryAddressService.selectAddressDetailByAddressId(orderInfo.getDiliveryId()));
        }
        //填充交易对手方信息
        fillTradeMatchDetailInfo(orderInfo);
        return orderInfo;
    }

    @Override
    public void updateOrderStatus(OrderInfo orderInfo) {
        orderDao.updateByPrimaryKeySelective(orderInfo);
    }

    @Override
    public OrderInfo selectOrderInfoByOrderSn(String orderSn) {
        return orderDao.selectOrderInfoByOrderSn(orderSn);
    }

    @Override
    public void delete(Long orderId) {
        orderDao.deleteByOrderId(orderId);
    }

    private void fillTradeMatchDetailInfo(OrderInfo orderInfo) {
        //根据订单编号查询委售单详情
        TradeEntrust tradeEntrust = tradeEntrustService.getTradeEntrustByOrderSn(orderInfo.getSn());
        if (tradeEntrust != null) {
            //查询交易对手方信息
            String bs = "";
            if (tradeEntrust.getEntrustBs().equals(EnumEntustBSType.SELL.getCode().toString())) {
                bs = EnumEntustBSType.BUY.getCode().toString();
            } else {
                bs = EnumEntustBSType.SELL.getCode().toString();
            }
            List<TradeMatchDetail> tradeMatchDetailList = tradeMatchService.selectCounterpartyTradeMatchDetailListforView(tradeEntrust.getId(), bs);
            orderInfo.setTradeMatchDetailList(tradeMatchDetailList);
        }
    }

    /**
     * 控制金莱花旗下产品只允许金莱花号段会员购买
     * 同时非金莱花商品也不允许金莱花会员购买
     * 不满足下单条件的均提示购买失败
     */
    private void validateGoldenFlower(String goodsCode, UserAccountDTO users) {
        String account = users.getFundAccount().substring(1);
        if (isGoldenFlower(goodsCode)) {
            if (StringUtil.isNotEmpty(goldenFlowerNumberSegment) &&
                    !account.startsWith(goldenFlowerNumberSegment)) {
                //是金莱花商品，但不是金莱花会员，不允许购买
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1039.getErrorNo(), EnumBusinessCode.BUSINESS_1039.getErrorInfo());
            }
        } else {
            if (StringUtil.isNotEmpty(goldenFlowerNumberSegment) &&
                    account.startsWith(goldenFlowerNumberSegment)) {
                //不是金莱花商品，但是金莱花会员，不允许购买
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1040.getErrorNo(), EnumBusinessCode.BUSINESS_1040.getErrorInfo());
            }
        }
    }

    //判断是否金莱花商品
    protected Boolean isGoldenFlower(String goodsCode) {
        String limitGoodsCode = BusinessParamHelper.getStringValue(bussinessParamService, EnumBussinessParam.GOLDEN_FLOWER_GOODS, null);
        String[] goodsCodeArray = StringUtils.tokenizeToStringArray(limitGoodsCode, ",");
        for (String temp : goodsCodeArray) {
            if (temp.equalsIgnoreCase(goodsCode)) {
                return true;
            }
        }
        return false;
    }
}
